package edu.wright.ceg4980.year2013.keyboard;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.border.Border;

@SuppressWarnings("serial")
public class MainScreen extends JPanel {
	private static enum Step {WELCOME, ENTER_PASSWORD, PRACTICE_PASSWORD, COLLECT_DATA, SAVE_RESULTS};
	
	private static final String[] STEPS;
	
	private static final int NUM_PRACTICE_TRIES = 2;
	
	private static final int NUM_COLLECTION_TRIES = 2;
	
	private Step currentStep;
	
	private int practiceTriesLeft, collectionTriesLeft;
	
	private String correctPassword;
	
	private KeySequenceData[] collectedData;
	
	private WelcomeScreen welcomeScreen;
	
	private EnterPasswordScreen enterPasswordScreen;
	
	private PracticeScreen practiceScreen;
	
	private CollectionScreen collectionScreen;
	
	private SaveScreen saveScreen;
	
	private JList<String> stepList;
	
	private JButton nextButton;
	
	private CardLayout mainPanelLayout;
	
	private JPanel mainPanel;
	
	static {
		STEPS = new String[Step.values().length];
		STEPS[Step.WELCOME.ordinal()] = "1. Welcome";
		STEPS[Step.ENTER_PASSWORD.ordinal()] = "2. Enter Password";
		STEPS[Step.PRACTICE_PASSWORD.ordinal()] = "3. Practice Password";
		STEPS[Step.COLLECT_DATA.ordinal()] = "4. Collect Data";
		STEPS[Step.SAVE_RESULTS.ordinal()] = "5. Save Results";
	}
	
	public MainScreen() {
		super(new BorderLayout());
		
		currentStep = Step.WELCOME;
		
		collectedData = new KeySequenceData[NUM_COLLECTION_TRIES];
		
		Border border = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK), BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		stepList = new JList<String>(STEPS);
		stepList.setCellRenderer(new StepListCellRenderer());
		stepList.setBorder(border);
		stepList.setEnabled(false);
		stepList.setSelectedIndex(0);
		
		nextButton = new JButton("Next");
		
		JButton restartButton = new JButton("Restart");
		
		JPanel centerPanel = new JPanel(new BorderLayout());
		
		mainPanelLayout = new CardLayout();
		mainPanel = new JPanel(mainPanelLayout);
		
		welcomeScreen = new WelcomeScreen();
		
		enterPasswordScreen = new EnterPasswordScreen();
		
		practiceScreen = new PracticeScreen();
		
		collectionScreen = new CollectionScreen();
		
		saveScreen = new SaveScreen();
		
		JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 5));
		
		add(stepList, BorderLayout.WEST);
		add(centerPanel, BorderLayout.CENTER);
			centerPanel.add(mainPanel, BorderLayout.CENTER);
				mainPanel.add(welcomeScreen, STEPS[Step.WELCOME.ordinal()]);
				mainPanel.add(enterPasswordScreen, STEPS[Step.ENTER_PASSWORD.ordinal()]);
				mainPanel.add(practiceScreen, STEPS[Step.PRACTICE_PASSWORD.ordinal()]);
				mainPanel.add(collectionScreen, STEPS[Step.COLLECT_DATA.ordinal()]);
				mainPanel.add(saveScreen, STEPS[Step.SAVE_RESULTS.ordinal()]);
			centerPanel.add(southPanel, BorderLayout.SOUTH);
				southPanel.add(nextButton);
				southPanel.add(restartButton);
				
		nextButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				switch (currentStep) {
				case WELCOME:
					enterPasswordScreen.clear();
					currentStep = Step.ENTER_PASSWORD;
					break;
				case ENTER_PASSWORD:
					correctPassword = enterPasswordScreen.getPassword1();
					LinkedList<String> pswdErrors = MainScreen.validatePassword(correctPassword);
					if (pswdErrors.isEmpty()) {
						String pswd2 = enterPasswordScreen.getPassword2();
						if (correctPassword.equals(pswd2)) {
							currentStep = Step.PRACTICE_PASSWORD;
							practiceTriesLeft = NUM_PRACTICE_TRIES;
							practiceScreen.setCorrectPassword(correctPassword);
							practiceScreen.setTries(NUM_PRACTICE_TRIES);
							practiceScreen.clearPassword();
							break;
						} else {
							pswdErrors.add("The re-entered password does not match the original password.");
						}
					}

					enterPasswordScreen.setErrorList(pswdErrors);
					return;
				case PRACTICE_PASSWORD:
					String pswd = new String(practiceScreen.getEnteredPassword());
					if (correctPassword.equals(pswd)) {
						--practiceTriesLeft;
						if (practiceTriesLeft == 0) {
							currentStep = Step.COLLECT_DATA;
							collectionTriesLeft = NUM_COLLECTION_TRIES;
							collectionScreen.setCorrectPassword(correctPassword);
							collectionScreen.setTries(NUM_COLLECTION_TRIES);
							collectionScreen.clearPassword();
						} else {
							practiceScreen.setTries(practiceTriesLeft);
							practiceScreen.clearPassword();
						}
					} else {
						JOptionPane.showMessageDialog(MainScreen.this.nextButton, "The password you typed is incorrect", "Incorrect Password", JOptionPane.ERROR_MESSAGE);
					}
					practiceScreen.clearPassword();
					break;
				case COLLECT_DATA:
					KeySequenceData data = collectionScreen.getTypingData();
					if (data != null) {
						--collectionTriesLeft;
						collectedData[collectionTriesLeft] = data;
						if (collectionTriesLeft == 0) {
							saveScreen.saveToFile(correctPassword, collectedData);
							currentStep = Step.SAVE_RESULTS;
						} else {
							collectionScreen.setTries(collectionTriesLeft);
							collectionScreen.clearPassword();
						}
					}
					collectionScreen.clearTypingData();
					break;
				case SAVE_RESULTS:
					restart();
					return;
				default:
					return;
				}
				
				int i = currentStep.ordinal();
				stepList.setSelectedIndex(i);
				mainPanelLayout.show(mainPanel, STEPS[i]);
			}
		});
		
		restartButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				MainScreen.this.restart();
			}
		});
	}
	
	private void restart() {
		currentStep = Step.WELCOME;
		
		int i = Step.WELCOME.ordinal();
		stepList.setSelectedIndex(i);
		mainPanelLayout.show(mainPanel, STEPS[i]);
	}

	private static LinkedList<String> validatePassword(String password) {
		final int MIN_PASSWORD_LENGTH = 10;
		
		LinkedList<String> result = new LinkedList<String>();
		
		if (password.length() < MIN_PASSWORD_LENGTH) {
			result.add("The password must be at least 10 characters long");
		}
		
		return result;
	}
	
	private static class StepListCellRenderer extends JLabel implements ListCellRenderer<String> {
		private Font defaultFont, selectedFont;
		
		public StepListCellRenderer() {
			defaultFont = getFont().deriveFont(Font.PLAIN);
			selectedFont = defaultFont.deriveFont(Font.BOLD);
		}
		
		public Component getListCellRendererComponent(JList<? extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) {
			setText(value);
			if (isSelected) {
				setFont(selectedFont);
			} else {
				setFont(defaultFont);
			}
			
			return this;
		}
	}
}
